package rs.udd.web.controller;

import static rs.udd.service.util.SecurityUtil.ADVERTISER_OR_ADMIN_ROLE;

import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpSession;
import javax.validation.Valid;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import rs.udd.exceptions.UddException;
import rs.udd.service.SearchService;
import rs.udd.service.document.model.RequiredHighlight;
import rs.udd.service.dto.search.PrepareSearchDto;
import rs.udd.service.dto.search.SearchAdvertDto;
import rs.udd.service.dto.search.SearchAdvertsResultDto;
import rs.udd.service.dto.search.SearchAgentCvDto;
import rs.udd.service.dto.search.SearchAgentCvResultDto;

@Controller
@RequestMapping({ "search", "/search", "/search/" })
public class SearchController {

	private final Logger LOGGER = LogManager.getLogger(getClass());

	@Autowired
	private SearchService searchService;

	@RequestMapping(method = RequestMethod.GET)
	public String prepareSearch(Model model) {
		LOGGER.info("Prepare search");

		try {
			PrepareSearchDto dto = searchService.prepareSearch();
			model.addAttribute("categories", dto.getCategories());
			model.addAttribute("advertisers", dto.getAdvertisers());
			model.addAttribute("searchAdvertDto", new SearchAdvertDto());
			model.addAttribute("searchAgentCvDto", new SearchAgentCvDto());
			return "common/search";
		} catch (UddException e) {
			LOGGER.error("Error while preparing search.", e);
			model.addAttribute("message", e.getMessage());
			return "error/error";
		}
	}

	@RequestMapping(value = "/did-you-mean", method = RequestMethod.GET)
	public String performAdvertSearch(HttpSession session, Model model) {
		SearchAdvertDto searchDto = (SearchAdvertDto) session.getAttribute("searchDto");
		session.setAttribute("searchDto", null);
		return performAdvertSearch(searchDto, model, session);
	}
	
	@RequestMapping(method = RequestMethod.POST)
	public String performAdvertSearch(@ModelAttribute("searchAdvertDto") SearchAdvertDto searchDto, Model model, HttpSession session) {
		LOGGER.info("Searching...");

		try {
			List<RequiredHighlight> suggestions = new ArrayList<RequiredHighlight>();
			List<SearchAdvertsResultDto> searchResults = searchService.performAdvertSearch(searchDto, suggestions);
			
			model.addAttribute("searchResults", searchResults);
			if (searchResults.isEmpty()) {
				model.addAttribute("suggestions", suggestions);
				session.setAttribute("searchDto", searchDto);
			}
			
			LOGGER.info("Search results: " + searchResults.size());
			LOGGER.info("Suggestions: " + suggestions.size());
			
			return "common/searchResults";
		} catch (UddException e) {
			LOGGER.error("Error while performing search.", e);
			model.addAttribute("message", e.getMessage());
			return "error/error";
		}
	}
	
	@RequestMapping(value = "/more-like-this/{fileName}", method = RequestMethod.GET)
	public String performMoreLikeThis(@PathVariable("fileName") String fileName, Model model) {
		LOGGER.info("More like this: " + fileName);
		List<SearchAdvertsResultDto> results = searchService.performMoreLikeThisSearch(fileName);
		model.addAttribute("searchResults", results);
		return "common/moreLikeThis";
	}

	@PreAuthorize(ADVERTISER_OR_ADMIN_ROLE)
	@RequestMapping(value = "/searchAgents", method = RequestMethod.POST)
	public String performAgentSearch(@Valid @ModelAttribute("searchAgentCvDto") SearchAgentCvDto searchAgentDto, BindingResult result, Model model) throws UddException {
		LOGGER.info("Searching for agents...");
		
		if (result.hasErrors()) {
			LOGGER.error("Binding error: " + result);
			return "common/search";
		}
		
		List<SearchAgentCvResultDto> searchResults = searchService.performAgentSearch(searchAgentDto);
		LOGGER.info("Search results: " + searchResults.size());
		
		model.addAttribute("searchResults", searchResults);

		return "common/searchAgentResults";
	}
	
}
